using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Serialization;
using System.Configuration;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using Pavilion;
using Pavilion.Communications;
using Pavilion.GameTools;

namespace PavilionGame
{
    public class Engine : Microsoft.Xna.Framework.Game
    {
        private GameController gameController;
        private GraphicsDeviceManager graphics;
        private ServiceController<UpdateGameService> service;
        private bool isPaused, pausePending;

        public Engine() : base()
        {
            gameController = new GameController();
            graphics = new GraphicsDeviceManager(this);
            service = new ServiceController<UpdateGameService>(new UpdateGameService(), typeof(IUpdateGameService), 8000);
            this.Disposed += (sender, e) => service.Disconnect();

            IsMouseVisible = true;
            //this.Activated += (sender, e) => { this.IsMouseVisible = false; };
            //this.Deactivated += (sender, e) => { this.IsMouseVisible = true; };

            GameItemManager.Instance.GameItemAdded += (gameItem) =>
            {
                gameItem.GameToolLoaded += (innerGameItem, gameTool) =>
                {
                    if (!(gameTool is NodeTool))
                        return;

                    NodeTool nodeTool = gameTool as NodeTool;

                    nodeTool.NodeLoaded += (nodeScript, node) =>
                    {
                        ResourceItem resource = ResourceManager.Instance.ResourceCollection.First(x => x.ObtainResourceCollection<NodeScriptCollection>().Contains(nodeScript));
                        DesignerClient.Instance.TransferDataThreaded(proxy => proxy.NodeLoaded(resource.Name, nodeScript.Name, UpdateGameService.CreateNodeStringCollection(node.ParentContainer), node.Name));
                    };
                    nodeTool.NodeUnloaded += (nodeScript, node) =>
                    {
                        ResourceItem resource = ResourceManager.Instance.ResourceCollection.First(x => x.ObtainResourceCollection<NodeScriptCollection>().Contains(nodeScript));
                        DesignerClient.Instance.TransferDataThreaded(proxy => proxy.NodeUnloaded(resource.Name, nodeScript.Name, UpdateGameService.CreateNodeStringCollection(node.ParentContainer), node.Name));
                    };
                };
            };
        }

        private string LoadResourceDirectory()
        {
            string mainDirectory = AppDomain.CurrentDomain.BaseDirectory;
            mainDirectory = mainDirectory.Substring(0, mainDirectory.Length - 1);

            while (!Directory.Exists(mainDirectory + @"\GameContent\"))
                mainDirectory = Directory.GetParent(mainDirectory).FullName;

            return mainDirectory + @"\GameContent\";
        }

        protected override void Initialize()
        {
            GameEngine.Initialize(this, Services, GraphicsDevice, LoadResourceDirectory());

            graphics.PreferredBackBufferHeight = 720;
            graphics.PreferredBackBufferWidth = 1280;

            graphics.ApplyChanges();

            base.Initialize();
        }

        protected override void LoadContent()
        {
            gameController.LoadGame();

            DrawManager.Instance.GameFont = Content.Load<SpriteFont>(@"Content\Fonts\Papyrus");

            service.Connect();
            DesignerClient.Instance.Connect();

            base.LoadContent();
        }

        protected override void UnloadContent()
        {
            base.UnloadContent();
        }

        protected override void Update(GameTime gameTime)
        {
            base.Update(gameTime);

            if (service.GameService.IsTransferring)
                return;

            if (Keyboard.GetState().IsKeyDown(Keys.P))
                pausePending = true;

            if (pausePending && Keyboard.GetState().IsKeyUp(Keys.P))
            {
                pausePending = false;
                isPaused = !isPaused;
            }

            if (!isPaused)
                gameController.Update(gameTime);

            if (Keyboard.GetState().IsKeyDown(Keys.H))
                ReloadGame();
        }

        private void ReloadGame()
        {
            gameController.LoadGame();

            DesignerClient.Instance.TransferDataThreaded(proxy => proxy.DisableAllCurrentlyPlayingNodes());
            DesignerClient.Instance.TransferDataThreaded(proxy => proxy.RequestDataTransfer());
        }

        protected override void Draw(GameTime gameTime)
        {
            graphics.GraphicsDevice.Clear(Color.WhiteSmoke);
            DrawManager.Instance.Begin(SpriteSortMode.Immediate, BlendState.NonPremultiplied);
            gameController.Draw();
            DrawManager.Instance.End();

            base.Draw(gameTime);
        }
    }
}
